<?php
#
# dmBridge: a data access framework for CONTENTdm(R)
#
# Copyright © 2009, 2010, 2011 Board of Regents of the Nevada System of Higher
# Education, on behalf of the University of Nevada, Las Vegas
#

/**
 * @author Alex Dolski <alex.dolski@unlv.edu>
 * @license http://www.opensource.org/licenses/mit-license.php
 */
class DMFile {

	/**
	 * @var string
	 */
	private $pathname;

	/**
	 * @param int byte_size
	 * @param string standard SI, IEC, or JEDEC
	 * @return string
	 * @see getUnitSymbolForByteSize()
	 */
	public static function getUnitsForByteSize($byte_size,
			$standard = "SI") {
		switch ($standard) {
		case "JEDEC":
			if ($byte_size < 1024) {
				return "bytes";
			} else if ($byte_size < pow(1024, 2)) {
				return "kilobytes";
			} else if ($byte_size < pow(1024, 3)) {
				return "megabytes";
			} else if ($byte_size < pow(1024, 4)) {
				return "gigabytes";
			}
			break;
		case "IEC":
			if ($byte_size < 1024) {
				return "bytes";
			} else if ($byte_size < pow(1024, 2)) {
				return "kibibytes";
			} else if ($byte_size < pow(1024, 3)) {
				return "mebibytes";
			} else if ($byte_size < pow(1024, 4)) {
				return "gibibytes";
			} else if ($byte_size < pow(1024, 5)) {
				return "tebibytes";
			} else if ($byte_size < pow(1024, 6)) {
				return "pebibytes";
			} else if ($byte_size < pow(1024, 7)) {
				return "exbibytes";
			} else if ($byte_size < pow(1024, 8)) {
				return "zebibytes";
			} else if ($byte_size < pow(1024, 9)) {
				return "yobibytes";
			}
			break;
		case "SI":
			if ($byte_size < 1000) {
				return "bytes";
			} else if ($byte_size < pow(1024, 2)) {
				return "kilobytes";
			} else if ($byte_size < pow(1024, 3)) {
				return "megabytes";
			} else if ($byte_size < pow(1024, 4)) {
				return "gigabytes";
			} else if ($byte_size < pow(1024, 5)) {
				return "terabytes";
			} else if ($byte_size < pow(1024, 6)) {
				return "petabytes";
			} else if ($byte_size < pow(1024, 7)) {
				return "exabytes";
			} else if ($byte_size < pow(1024, 8)) {
				return "zettabytes";
			} else if ($byte_size < pow(1024, 9)) {
				return "yottabytes";
			}
			break;
		}
		return null;
	}
	
	/**
	 * In all cases, bytes less than one kilobyte are returned with a "b"
	 * suffix, per IEEE 1541.
	 * 
	 * @param int byte_size
	 * @param string standard SI, IEC, or JEDEC
	 * @return string
	 * @see getUnitsForByteSize()
	 */
	public static function getUnitSymbolForByteSize($byte_size,
			$standard = "SI") {
		switch ($standard) {
		case "JEDEC":
			if ($byte_size < 1024) {
				return "b";
			} else if ($byte_size < pow(1024, 2)) {
				return "K";
			} else if ($byte_size < pow(1024, 3)) {
				return "M";
			} else if ($byte_size < pow(1024, 4)) {
				return "G";
			}
			break;
		case "IEC":
			if ($byte_size < 1024) {
				return "b";
			} else if ($byte_size < pow(1024, 2)) {
				return "Ki";
			} else if ($byte_size < pow(1024, 3)) {
				return "Mi";
			} else if ($byte_size < pow(1024, 4)) {
				return "Gi";
			} else if ($byte_size < pow(1024, 5)) {
				return "Ti";
			} else if ($byte_size < pow(1024, 6)) {
				return "Pi";
			} else if ($byte_size < pow(1024, 7)) {
				return "Ei";
			} else if ($byte_size < pow(1024, 8)) {
				return "Zi";
			} else if ($byte_size < pow(1024, 9)) {
				return "Yi";
			}
			break;
		case "SI":
			if ($byte_size < 1000) {
				return "b";
			} else if ($byte_size < pow(1024, 2)) {
				return "k";
			} else if ($byte_size < pow(1024, 3)) {
				return "M";
			} else if ($byte_size < pow(1024, 4)) {
				return "G";
			} else if ($byte_size < pow(1024, 5)) {
				return "T";
			} else if ($byte_size < pow(1024, 6)) {
				return "P";
			} else if ($byte_size < pow(1024, 7)) {
				return "E";
			} else if ($byte_size < pow(1024, 8)) {
				return "Z";
			} else if ($byte_size < pow(1024, 9)) {
				return "Y";
			}
			break;
		}
		return null;
	}

	/**
	 * @param string pathname
	 */
	public function __construct($pathname) {
		$this->setPathname($pathname);
	}

	/**
	 * @return string The last path component.
	 */
	public function __toString() {
		return $this->getLastPathComponent();
	}

	/**
	 * @param mixed obj
	 * @return boolean
	 */
	public function equals($obj) {
		if (!$obj instanceof DMFile) {
			return false;
		}
		return ($obj->getPathname() == $this->getPathname());
	}

	/**
	 * @return string
	 */
	public function getExtension() {
		$tmp = explode(".", $this->getLastPathComponent());
		if (count($tmp) > 1) {
			return $tmp[count($tmp) - 1];
		}
		return null;
	}

	/**
	 * @param int precision
	 * @return string A human-readable size string in SI units.
	 */
	public function getHumanReadableSize($precision = 2) {
		$bytes = $this->getSize();
		if ($bytes < 1000) {
			return $bytes . ' b';
		} else if ($bytes < pow(1000, 2)) {
			return round($bytes / 1000, $precision) . " k";
		} else if ($bytes < pow(1000, 3)) {
			return round($bytes / pow(1000, 2), $precision) . " M";
		} elseif ($bytes < pow(1000, 4)) {
			return round($bytes / pow(1000, 3), $precision) . " G";
		} elseif ($bytes >= pow(1000, 5)) {
			return round($bytes / pow(1000, 4), $precision) . " T";
		} elseif ($bytes >= pow(1000, 6)) {
			return round($bytes / pow(1000, 5), $precision) . " P";
		} elseif ($bytes >= pow(1000, 7)) {
			return round($bytes / pow(1000, 6), $precision) . " E";
		} elseif ($bytes >= pow(1000, 8)) {
			return round($bytes / pow(1000, 7), $precision) . " Z";
		} elseif ($bytes >= pow(1000, 9)) {
			return round($bytes / pow(1000, 8), $precision) . " Y";
		}
	}

	/**
	 * @return string
	 */
	public function getLastPathComponent() {
		return basename($this->getPathname());
	}

	/**
	 * Returns a best guess at the file's media type based on its extension.
	 * Wraps DMMediaType::getTypeForExtension(). May return null.
	 * 
	 * @return DMMediaType
	 */
	public function getMediaType() {
		return DMMediaType::getTypeForExtension($this->getExtension());
	}

	/**
	 * Returns the base filename without any extension.
	 * 
	 * @return string
	 */
	public function getNameWithoutExtension() {
		$basename = basename($this->getPathname());
		$tmp = explode(".", $basename);
		if (count($tmp) == 1) {
			return $basename;
		}
		array_pop($tmp);
		return implode(".", $tmp);
	}

	/**
	 * @return string
	 */
	public function getPathname() {
		return $this->pathname;
	}

	/**
	 * @param string pathname
	 */
	public function setPathname($pathname) {
		$this->pathname = $pathname;
	}

	/**
	 * @return int File size, in bytes.
	 * @throws DMFileNotFoundException
	 */
	public function getSize() {
		if (!file_exists($this->getPathname())) {
			throw new DMFileNotFoundException($this->getPathname());
		}
		return filesize($this->getPathname());
	}

}
